package com.bitoon.basketdudes.web.admin;

import com.bitoon.basketdudes.javamail.Mail;
import com.bitoon.basketdudes.web.BaseAction;
import com.bitoon.basketdudes.web.jpa.AdmRolSeccion;
import com.bitoon.basketdudes.web.jpa.PersistenceManager;
import com.bitoon.basketdudes.web.jpa.AdmUsuario;
import com.opensymphony.xwork2.ActionContext;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import java.util.*;
import java.util.ArrayList;
import javax.persistence.*;
import org.apache.log4j.Logger;

public class LoginAction extends BaseAction {

    private Logger log = Logger.getLogger(LoginAction.class);
    //datos del formulario de login
    private String nombre;
    private String contrasena;
    private String contrasenaSHA1;
    private String email;
    private String hash;
    private boolean no_encontrado;

    private String [][] secciones_redireccion = {{"./lista_usuarios.action","0"},
                                                {"./lista_noticias.action", "1"},
                                                {"./estadisticasGenerales.action", "2"},
                                                {"./.action", "3"},
                                                {"./lista_usuariosAdmin.action", "4"}};
    private String url;

    //acceso a la clase estatica BaseActionAdmin
    private BaseActionAdmin bsaadmin = BaseActionAdmin.getInstance();

    @Override
    public String execute(){

        AdmUsuario user = null;

        //ponemos el l enguaje por defecto si no existe
        fijarIdioma();

        //miramos si ya esta logado(tendremos que redirigir a una accion del menu)
        if (!session.containsKey("admin_userId")){
            if(nombre!=null && contrasenaSHA1!=null){
                user = getUsuarioAdm(nombre, contrasenaSHA1);
            }

            if(user==null){
                log.debug("[Login] input");
                return "input";
            }else{
                //si el usuario es válido ponemos en sesión los siguientes datos:
                // - id
                // - objeto
                log.debug("login in");
                session.put("admin_userId", user.getId());
                session.put("admin_userLogado", user);
            }
        }//fin si esta ya logado
        else{
            log.debug("logado");
            urluserLogado();
            return "logado";
        }

        return SUCCESS;
    }

    private void fijarIdioma(){
        //ponemos el l enguaje por defecto si no existe

        String idiomaContexto = ActionContext.getContext().getLocale().getLanguage();
        //log.debug("Idioma del contexto: " + idiomaContexto);

        String language = (String)session.get("bd_lang");

        if(language==null){
            boolean sw=false;
            //buscamos el idioma dentro de nuestros idiomas permitidos
            for(String i:getBsaadmin().getIdiomas()){
                if(i.compareToIgnoreCase(idiomaContexto)==0){
                    sw=true;
                }
            }

            if(sw==true){
                //el idioma por defecto del navegador nos vale como idioma
                session.put("bd_lang", idiomaContexto.toLowerCase());
            }else{
                //ponemos como idioma el por defecto nuestro
                session.put("bd_lang", getBsaadmin().getIdiomaPrincipal());
            }
        }
        ActionContext.getContext().setLocale(new Locale((String)session.get("bd_lang")));
        idioma = (String)session.get("bd_lang");
        //log.debug("Idioma de la aplicacion: " + (String)session.get("bd_lang"));
    }

    public String logout() throws Exception {
        //eliminamos las variables de la sesión
        session.remove("admin_userId");
        session.remove("admin_rolId");
        session.remove("admin_userLogado");

        url = "";

        return SUCCESS;
    }

    public String transicion(){
        //ponemos el l enguaje por defecto si no existe
        fijarIdioma();
        return SUCCESS;
    }

    public String recordar() {
        String retorno = SUCCESS;

        EntityManager em = null;

        log.debug("[recordar] entro");

        //ponemos el l enguaje por defecto si no existe
        fijarIdioma();

        try {
            em = getBsaadmin().getEmfAdmin().createEntityManager(); // checked

            Query q = em.createNamedQuery("AdmUsuario.findByEmail");
            q.setParameter("email", getEmail().toLowerCase());
            log.info("[recordar] Buscando usuario. " + getEmail());
            AdmUsuario u = (AdmUsuario)q.getSingleResult();

            if(u!=null){
                String activacion = generarActivacion(u.getNick(),u.getEmail(),u.getFUltimo());
                mandarMailRecuperacion(u.getNick(), getEmail(), activacion);
            }

        } catch (NoResultException e) {
            // No existen datos para la activacion del usuario
            log.debug("[recordar] No existe el usuario que esta intentando recordar.");
            setNoEncontrado(true);
            retorno = NOT_FOUND;
        } catch (Exception e) {
            log.error("[recordar]: Error: ", e);
        } finally {
            try { em.close(); } catch (Exception e) { }
        }

        return retorno;
    }

    private void mandarMailRecuperacion(String nick, String email, String activacion) {
            Mail jmail = new Mail();

            String asunto = "Password recovery at BasketDudes Backend";
            String cuerpo = "Your Bitoon username is:\n\n" + nick + "\n\nTo change your password visit this link:\n\n";
            cuerpo += "http://192.168.1.13:8080/BasketDudesAdmin/backend/modificar_contrasenya.action?email=" + email.toLowerCase() + "&hash=" + activacion;

            if (idioma.equals("es")) {
                asunto = "Recuperación de contraseña en backend de Basketdudes";
                cuerpo = "Tu nombre de usuario registrado en el sistema de administración es:\n\n" + nick + "\n\nPara recuperar tu contraseña visita el siguiente enlace:\n\n";
                cuerpo += "http://192.168.1.13:8080/BasketDudesAdmin/backend/modificar_contrasenya.action?email=" + email.toLowerCase() + "&hash=" + activacion;
            }

            jmail.sendMail(email, asunto, cuerpo);
    }

    private String generarActivacion(String nick,String email,Date f_ultimo) {
        //calculas una clave en SHA1SHA-1 devuelve como resultado una cadena de 40 caracteres de
        //longitud, independientemente de la longitud de la cadena original.
        String message = "";

        message = nick + email + f_ultimo.toString();

        message = getSHA1(message);

        log.debug("[generarActivacion] Cadena: "+message + " SHA1: "+hash);

        return message;
    }

    private String getSHA1(String message){
        MessageDigest md;
        byte[] buffer, digest;
        String has = "";

        try {
            buffer = message.getBytes();
            md = MessageDigest.getInstance("SHA1");
            md.update(buffer);
            digest = md.digest();

            for(byte aux : digest) {
                int b = aux & 0xff;
                if (Integer.toHexString(b).length() == 1) has += "0";
                has += Integer.toHexString(b);
            }
        }catch(NoSuchAlgorithmException e) {
            log.debug("[getSHA1] error:",e);
        }

        return has;
    }

    public String modificarPassword() {
        String retorno = SUCCESS;

        log.debug("email: " + email + ", hash: " + getHash());

        AdmUsuario a = null;
        EntityManager em = null;

        //ponemos el l enguaje por defecto si no existe
        fijarIdioma();

        try {
            em = getBsaadmin().getEmfAdmin().createEntityManager(); // checked

            Query q = em.createNamedQuery("AdmUsuario.findByEmail");
            q.setParameter("email", email.toLowerCase());
            a = (AdmUsuario)q.getSingleResult();

            log.debug("[modificarPassword] UsuarioNick: " + a.getNick());

            //creo el hash SHA1 del usuario en la BD y lo comparo con el pasado en el email de recordar contraseña
            String nuevoHash = getSHA1(a.getNick()+a.getEmail()+a.getFUltimo().toString());

            log.debug("[modificarPassword] HashAntiguo: " + hash + "HashNuevo: " + nuevoHash);

            if (nuevoHash.equals(getHash())) {
                // El hash es válido
                // Grabamos en sesion el usuario que está modificando su password
                session.put("admin_usuarioModificandoPassword", a.getId());
            } else {
                retorno = NOT_FOUND;
                setNoEncontrado(true);
            }

        } catch (NoResultException e) {
            // No existen datos para la activacion del usuario
            log.debug("[modificarPassword] No existe el usuario que esta intentando reactivar");
            retorno = NOT_FOUND;
            setNoEncontrado(true);
        } catch (Exception e) {
            log.error("[modificarPassword]", e);
        } finally {
            try { em.close(); } catch (Exception e) { }
        }

        return retorno;
    }


    public String grabarModificacionPassword() {
        String retorno = SUCCESS;

        //log.debug("[nueva contrasenaSha1] sha1: " + getContrasenaSHA1());
        int idUsuarioModificandoPassword = (Integer)session.get("admin_usuarioModificandoPassword");
        //log.debug("idUsuarioModificandoPassword: " + idUsuarioModificandoPassword);

        //ponemos el l enguaje por defecto si no existe
        fijarIdioma();

        EntityManager em = null;

        try {
            em = getBsaadmin().getEmfAdmin().createEntityManager(); // checked

            AdmUsuario u = em.find(AdmUsuario.class, idUsuarioModificandoPassword);

            u.setPassword(getContrasenaSHA1());

            em.getTransaction().begin();
            em.persist(u);
            em.getTransaction().commit();

        } catch (Exception e) {
            log.error("[grabarModificacionPassword]", e);
        } finally {
            try { if (em.getTransaction().isActive()) { em.getTransaction().rollback(); } } catch (Exception e) { }
            try { em.close(); } catch (Exception e) { }
        }

        return retorno;
    }

    public String getContrasena() {
        return contrasena;
    }

    public void setContrasena(String password) {
        this.contrasena = password;
    }

    private AdmUsuario getUsuarioAdm(String nom, String password){
        AdmUsuario user = null;
        EntityManagerFactory emf = PersistenceManager.getInstance().getEntityManagerFactory(BaseAction.catalogos[1]);
        EntityManager em = null;
        Query q  = null;
        ArrayList<AdmRolSeccion> permisos = null;

        try{
            //sacamos de la BD el usuario si coincide
            em = emf.createEntityManager(); // checked
            q  = em.createNamedQuery("AdmUsuario.findByLogin");
            q.setParameter("nick", nom);
            q.setParameter("password", password);
            user = (AdmUsuario)q.getSingleResult();

            if(user!=null){
                //sacamos sus permisos
                permisos = new ArrayList<AdmRolSeccion>();
                boolean sw=false;
                for(int i=0;i<user.getRolId().getAdmRolSeccionList().size();++i){
                    permisos.add(user.getRolId().getAdmRolSeccionList().get(i));
                    //calculamos la url a la que redirigirle
                    if(permisos.get(i).getPermiso()>0 && sw == false){
                        asignarUrlRedireccion(i); //le paso el index de la accion
                        sw=true;
                    }
                }
                session.put("admin_permisos", permisos);
            }

        } catch (NoResultException e) {
            log.error("[getUsuarioAdm] Not found exception");
        } catch (Exception e) {
            log.error("[getUsuarioAdm] Error", e);
        } finally {
            try { em.close(); } catch (Exception e) { }
        }
        return user;
    }

    public void urluserLogado(){
        ArrayList<AdmRolSeccion> permisos = (ArrayList<AdmRolSeccion>)session.get("admin_permisos");
        boolean sw=false;
        for(int i=0;i<permisos.size();++i){
            //calculamos la url a la que redirigirle
            if(permisos.get(i).getPermiso()>0 && sw == false){
                asignarUrlRedireccion(i); //le paso el index de la accion
                sw=true;
            }
        }
    }

    public void asignarUrlRedireccion(int index){
        //log.debug(" index: " + index + "url" + secciones_redireccion[index][0]);
        url = secciones_redireccion[index][0]; //accion a la que redirigir
        session.put("seccion_navegacion", secciones_redireccion[index][1]); //id seccion BD
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getContrasenaSHA1() {
        return contrasenaSHA1;
    }

    public void setContrasenaSHA1(String contrasenaSHA1) {
        this.contrasenaSHA1 = contrasenaSHA1;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getHash() {
        return hash;
    }

    public void setHash(String hash) {
        this.hash = hash;
    }

    public boolean getNoEncontrado() {
        return no_encontrado;
    }

    public void setNoEncontrado(boolean no_encontrado) {
        this.no_encontrado = no_encontrado;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String[][] getSecciones_redireccion() {
        return secciones_redireccion;
    }

    public void setSecciones_redireccion(String[][] secciones_redireccion) {
        this.secciones_redireccion = secciones_redireccion;
    }

    public BaseActionAdmin getBsaadmin() {
        return bsaadmin;
    }

    public void setBsaadmin(BaseActionAdmin bsaadmin) {
        this.bsaadmin = bsaadmin;
    }

}
